#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# -----------------------------------------------------------------------------
"""
   cdocgen main function
"""

#__version__    = "0.3.2"   # Apr. 15, 2014
#__version__    = "0.3.1"   # Apr. 15, 2014
#__version__    = "0.3.0"   # Apr. 13, 2014
#__version__    = "0.2.4"   # Apr. 10, 2014
#__version__    = "0.2.3"   # Dec. 25, 2013
#__version__    = "0.2.2"   # Apr. 28, 2012
#__version__    = "0.2b"   # Feb.12, 2012
#__version__    = "0.2a"   # Feb.4, 2012
#__version__    = "0.2"   # Feb.2, 2012
#__version__    = "0.1a" # Feb.1, 2012
#__version__    = "0.1"  # Jan.31, 2012

#__version__    = "0.3.2-1"   # July. 1, 2016
#__version__    = "0.3.3-20170228"   # Feb. 28, 2017
#__version__    = "0.3.4"   # Mar. 6, 2017
#__version__    = "0.3.5-2017-4-18"   # 将md中的<p>换成<br>
#__version__    = "0.3.6-2017-6-29"   # 增加全局变量功能
#__version__    = "0.3.7-2017-6-30"   # 修改全局变量bug
#__version__    = "0.3.7a-2017-6-30"   # 修复字符串中文件误解析全局的bug
#__version__    = "0.3.7b-2017-7-8"   # 允许头部注释出现tab
#__version__     = "0.3.8.2017.7.11"  # 修复打包问题
#__version__     = "0.3.9.2018.5.3"  # 修复箭头问题
# __version__     = "0.3.10.2020.4.25"  # 修复全局变量识别中首字母大写的bug
__version__     = "0.3.11.2020.9.16"  # 增加STATIC容忍,修复参数成员变量误识别为输入gvar

main_version = __version__

import sys
import os
import codecs
import logging

try:
    from visio.cvisio import cvisio
except:
    # 为了考虑加密的兼容性问题，在cdocgen.exe不可用是使用pyc
    import os
    sys.path.append(os.path.split(os.path.abspath(sys.argv[0]))[0]+'/library.zip')
    from visio.cvisio import cvisio

from visio.tvisio import tvisio
import word.cword as cword
from common.cgrammar import cgrammar
from word.cmarkdown import mddoc

class cdoc(cgrammar):
    def __init__(self, name):
        cgrammar.__init__(self)
        self.fname = name
        self.tvisio = tvisio("trace")

    def clean(self):
        if self.flag_get('md'):
            self.output.close()
            return
        if self.flag_get('visio'):
            return 
        self.output.delete_template()
        self.output.update_file_field()

    def active_office(self, inputname='', outputname=''):
        # 如果未指定输入，输出文件，使用源文件名字自动命名
        # 如果未指定输入，指定输出，使用文件
        # 如果指定输入，未指定输出，自动使用输入文件作为输出
        # 如果指定输入，指定输出，正常使用

        self.curdir = os.path.abspath('.')
        self.image_dir = os.path.join(self.curdir, 'images')
        
        
        if self.flag_get('nodraw')==0:
            self.visio = cvisio(os.path.join(self.curdir, '__autodd__.vsdx'))
            if not os.path.exists(self.image_dir): os.makedirs(self.image_dir)
            
        if self.flag_get('visio'):
            return

        if self.flag_get('md'):
            if outputname == '':
                outputname = os.path.join(self.curdir, '__autodd__.md')
            self.output = mddoc(outputname)
            return
        # 后续对word的命名进行规定
        if inputname == '' and outputname == '':
            self.output = cword.cword(self.fname+'.doc')
            self.output.open_from_template(self.fname+'.doc')
        elif inputname == '' and outputname != '':
            self.output = cword.cword(self.fname+'.doc')
            self.output.open_from_template(outputname)
        elif inputname != '':
            self.output = cword.cword(inputname)
            self.output.open_default(outputname)

    def extend_printer(self, name, header, exp, depth):
        # 获取忽略标志
        #print 'doxy header', header
        word_flag = not header.has_key('ignore')

        # 扩展
        print('-----Adding func:', name, '@depth:', depth, ', Draw word=', word_flag)
        if self.flag_get('trace'):
            self.tvisio.draw_fun(name, exp, 0, 0, depth)
        elif self.flag_get('visio'):
            self.visio.draw_fun(name, exp, 0, 0, depth, self.image_dir)
        elif self.flag_get('md'):
            # 输出md文件
            self.output.insert_fun(name, header)
            if self.flag_get('nodraw') == 0:
                self.visio.draw_fun(name, exp, 0, 0, depth, self.image_dir)
        elif self.flag_get('nodraw') == 0:
            #print "before insert", name, word_flag, header
            if (word_flag):
                self.output.insert_fun(name, header)
                self.visio.draw_fun(name, exp, 0, 0, depth)
                self.output.insert_visio_pic(self.visio)
        pass

def version_info():
    print('version: ' + __version__)

def usage():
    prog = sys.argv[0].split('\\')[-1]
    usagestr = 'Usage: ' + prog +' [OPTIONS] [FILES]'+ u"""
用于从C语言(目前仅支持C语言)中的doxygen注释生成详细设计文件。
支持自动绘制visio格式流程图，并解析函数头部形成函数说明表。
注释风格推荐使用/*- */, 支持修改的全局变量输出判断。
By <kaikuo.zhuo@hotmail.com>, 2012,2013,2014,2015,2017, v%s

[OPTIONS]选项说明：
      -d,   --depth=DEPTH       设置在visio中流程图的调用层数
                                将被函数头部注释中的@depth覆盖.
            --force-depth=DEPTH 强制设置调用层数，不能被@depth覆盖
      -e,   --enhance           使用增强模式(reserved)
      -i,   --input=INFILE      设置word输入文件
      -o,   --output=OUTFILE    设置word输出文件
      -k,   --keyword=KEYFILE   设置语言的关键字文件
      -v,   --verbose           向终端输出函数结构
      -c,   --continue          使用continue的方式插入详细设计，保留模板
      -t,   --text              文本模式，用于绘制visio图
            --visio             只进行visio绘图，不生成word文件
            --md                只输出markdown文件，不生成word文件
            --nodraw            不进行visio绘图，不生成word文件
            --trace             进行画图的跟踪
            --filter=FILTER     用于过滤函数名称
      -h,   --help              帮助
            --version           打印版本信息

[FILES]文件名说明:
    支持 *.c, ??.c 通配符，支持通配符组合，如: "1.c module\*.c"等

如有疑问，随时联系. """%main_version
    #print usagestr
    print(usagestr)
    
    
class arg_map:
    def __init__(self):
        self.m = {}

    def flag_set(self, key, value):
        self.m[key] = value

    def flag_update(self, dst):
        for k, v in self.m.items():
            dst.flag_set(k, v)

if __name__ == "__main__":
    """
    CDocgen的主函数
    """
    import common.cglobal as cglobal
    import clang.clex as clex
    import clang.cyacc as cyacc

    import getopt
    import glob

    try:
        # 获取选项参数列表
        #    有效option在opts中
        #    后续的参数全部在args中
        opts, args = getopt.getopt(sys.argv[1:], 
                                   "hk:d:i:o:etcv",     # 短参数
                ["help", "keyword=", "depth=", "force-depth=", "filter=", "input=", "output=", 
                 "nodraw", "visio", "md", "debug", "enhance", "verbose", "trace", "text", "test", "continue", "version"])    # 长参数

        if (len(args) == 0 and len(opts)==0 ):
            usage()
            sys.exit(2)

        filelist = []
        docname = ""

        if (len(args) > 0):
            names = args
            for files in names:
                temp = glob.glob(files)
                for name in temp:
                    if not name in filelist:
                        filelist.append(name)

            # 这是自动命名的文件
            docname = cglobal.get_short_doc_name(filelist[0])
            #print filelist, docname; sys.exit(1)

        input_file = ""
        output_file = ""
        keyword_file = ""
        enhance = False

        amap = arg_map()
        amap.m['debug'] = 0

        for o, a in opts:
            if o in ('-d', '--depth'):
                # 设置深度时
                amap.flag_set('depth', int(a))
            elif o in ('-e', '--enhance'):
                enhance = True
            elif o in ('-i', '--input'):
                # 设置输入参数
                input_file = cglobal.get_full_name(a)
                #print temp, input_file
            elif o in ('-o', '--output'):
                # 设置输出文件
                output_file = cglobal.get_full_name(a)
            elif o in ('-k', '--keyword'):
                # 设置输出文件
                keyword_file = cglobal.get_full_name(a)
                amap.flag_set('keyword', keyword_file)
            elif o in ('-v', '--verbose'):
                amap.flag_set('verbose', 1)
                logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.DEBUG)
            elif o in ('-t', '--text'):
                amap.flag_set('text', 1)
            elif o in ('--debug'):
                amap.flag_set('debug', 1)
            elif o in ('--force-depth'):
                amap.flag_set('force-depth', int(a))
            elif o in ('--filter'):
                # 设置过滤器
                amap.flag_set('filter', a)
            elif o in ('--test'):
                # 设置过滤器
                amap.flag_set('test', 1)
            elif o in ('--trace'):
                amap.flag_set('nodraw', 1)
                amap.flag_set('trace', 1)
                print(u"\ncdocgen trace模式\n+++表示解析一个节点，---表示连接两个不同的节点")
            elif o in ('--nodraw'):
                # 不绘图
                amap.flag_set('nodraw', 1)
            elif o in ('--md'):
                amap.flag_set('md', 1)
            elif o in ('--visio'):
                # 只画visio
                amap.flag_set('visio', 1)
            elif o in ('-R', '--recursive'):
                amap.flag_set('recursive', 1)
            elif o in ('-c', '--continue'):
                amap.flag_set('continue', 1)
            elif o in ('-h', '--help'):
                usage()
                sys.exit(2)
            elif o in ('--version'):
                version_info()
                sys.exit(2)
            else:
                assert False, 'unknown option'

        gfun = cdoc(docname)
        myclex = clex.clex(gfun.comment_map)
        if (keyword_file != ""):
            myclex.load_keyword_from_file(keyword_file)

        print("+++Program flags:", amap.m)
        amap.flag_update(gfun)

        if (gfun.flag_get('test') == 1):
            try:
                gfun.active_office()
            except Exception as err:
                pass
            sys.exit(3)

        p = cyacc.cyacc(myclex, gfun, amap.m['debug'])
        if (enhance):
            import clang.ceyacc as ceyacc
            p = ceyacc.cyacc(myclex, gfun)
        print('+++Input file:', input_file)
        print('+++Output file:', output_file)
        import win32com.client
        try:
            # nodraw = 0表示需要visio和word
            if (gfun.flag_get('nodraw') == 0 or gfun.flag_get('md')):
                gfun.active_office(input_file, output_file)
        except Exception as err:
        #except EOFError, err:
            # 针对office的故障
            cglobal.print_com_err(err, 'cdocgen_300_active')

        # 打开文件，解析内容
        for name in filelist:
            print('===Parsing file', name)
            #f=open(name)
            try:
                f = codecs.open(name, 'r', 'gbk')
                data = f.read()
                res = p.parse(data,debug=0)
                f.close()

            except UnicodeDecodeError as e:
                f = codecs.open(name, 'r', 'utf-8')
                data = f.read()
                res = p.parse(data,debug=0)
                f.close()

        # 
        if gfun.flag_get('md') or (gfun.flag_get('nodraw') == 0 and gfun.flag_get('continue') != 1):
            gfun.clean()

        if gfun.flag_get('nodraw') == 0:
            gfun.visio.save(False)

    except getopt.GetoptError as err:
        # print help information and exit:
        print(str(err)) # will print something like "option -a not recognized"
        usage()
        sys.exit(2)
    
    except Exception as err:
        cglobal.print_com_err(err, 'final')

